/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.comut.crud.util;

import com.comut.crud.pojo.FindAndSet;
import com.comut.crud.pojo.fleet.Fleet;
import com.comut.crud.pojo.mobile.MobileUpdate;
import com.comut.crud.pojo.poi.Poi;
import com.comut.crud.pojo.user.User;
import com.comut.lib.error.ErrorCodes;
import com.comut.lib.exception.JSONMalFormedException;
import com.comut.lib.util.Utilities;
import com.google.gson.*;
import java.io.StringReader;
import java.util.Map.Entry;
import java.util.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

/**
 * Validate the json and prepare the json attributes to be used in sqlserver
 * statment
 *
 * @author asantos
 */
public final class ParseJson {

    private static Logger _logger = Logger.getLogger(ParseJson.class.getName());
    private static ParseJson _singleton;
    private static String trailerFindStr;
    private static String trailerUpdateStr;
    private static HashSet trailerFind;
    private static HashSet trailerUpdate;
    private static String groupFindStr;
    private static String groupUpdateStr;
    private static HashSet groupFind;
    private static HashSet groupUpdate;
    private static String groupTags;
    private static String subgroupFindStr;
    private static String subgroupUpdateStr;
    private static HashSet subgroupFind;
    private static HashSet subgroupUpdate;
    private static String userFindStr;
    private static String userUpdateStr;
    private static HashSet userFind;
    private static HashSet userUpdate;
    private static String driverFindStr;
    private static String driverUpdateStr;
    private static HashSet driverFind;
    private static HashSet driverUpdate;
    private static String driverGroupDocument;
    private static String driverGroupFindStr;
    private static String driverGroupUpdateStr;
    private static HashSet driverGroupFind;
    private static HashSet driverGroupUpdate;
    private static String poiFindStr;
    private static String poiUpdateStr;
    private static HashSet poiFind;
    private static HashSet poiUpdate;
    private static String poiCategory;
    private static String poiCategoryGroup;
    private static String poiXmlStr;
    private static HashSet poiXml;
    private static String poiDescription;
    private static String poiMax_auth_stop_time;
    private static String poiMetadata;
    private static String userName;
    private static String userEmail;
    
    private static String mobileFindStr;
    private static String mobileUpdateStr;
    private static HashSet mobileFind;
    private static HashSet mobileUpdate;    
    private static String mobileNotNullableStr;
    private static HashSet mobileNotNullable;
    
    private static String fleetFindStr;
    private static String fleetUpdateStr;
    private static HashSet fleetFind;
    private static HashSet fleetUpdate;

    private ParseJson() {
        ResourceBundle bundle = ResourceBundle.getBundle("dbFields");
        trailerFindStr = bundle.getString("trailerFind");
        trailerUpdateStr = bundle.getString("trailerUpdate");
        trailerFind = Utilities.getInstance().StrToHashSet(trailerFindStr, ",");
        trailerUpdate = Utilities.getInstance().StrToHashSet(trailerUpdateStr, ",");
        groupFindStr = bundle.getString("groupFind");
        groupUpdateStr = bundle.getString("groupUpdate");
        groupFind = Utilities.getInstance().StrToHashSet(groupFindStr, ",");
        groupUpdate = Utilities.getInstance().StrToHashSet(groupUpdateStr, ",");
        groupTags = bundle.getString("groupTags");
        subgroupFindStr = bundle.getString("subgroupFind");
        subgroupUpdateStr = bundle.getString("subgroupUpdate");
        subgroupFind = Utilities.getInstance().StrToHashSet(subgroupFindStr, ",");
        subgroupUpdate = Utilities.getInstance().StrToHashSet(subgroupUpdateStr, ",");
        userFindStr = bundle.getString("userFind");
        userUpdateStr = bundle.getString("userUpdate");
        userFind = Utilities.getInstance().StrToHashSet(userFindStr, ",");
        userUpdate = Utilities.getInstance().StrToHashSet(userUpdateStr, ",");

        driverFindStr = bundle.getString("driverFind");
        driverUpdateStr = bundle.getString("driverUpdate");
        driverFind = Utilities.getInstance().StrToHashSet(driverFindStr, ",");
        driverUpdate = Utilities.getInstance().StrToHashSet(driverUpdateStr, ",");
        driverGroupDocument = bundle.getString("driverGroupDocument");

        driverGroupFindStr = bundle.getString("driverGroupFind");
        driverGroupUpdateStr = bundle.getString("driverGroupUpdate");
        driverGroupFind = Utilities.getInstance().StrToHashSet(driverGroupFindStr, ",");
        driverGroupUpdate = Utilities.getInstance().StrToHashSet(driverGroupUpdateStr, ",");

        poiFindStr = bundle.getString("poiFind");
        poiUpdateStr = bundle.getString("poiUpdate");
        poiFind = Utilities.getInstance().StrToHashSet(poiFindStr, ",");
        poiUpdate = Utilities.getInstance().StrToHashSet(poiUpdateStr, ",");

        poiCategory = bundle.getString("poiCategory");
        poiCategoryGroup = bundle.getString("poiCategoryGroup");

        poiXmlStr = bundle.getString("poiXml");
        poiXml = Utilities.getInstance().StrToHashSet(poiXmlStr, ",");
        
        poiDescription = bundle.getString("poiDescription");
        poiMax_auth_stop_time = bundle.getString("poiMax_auth_stop_time");
        poiMetadata = bundle.getString("poiMetadata");

        
        userName = bundle.getString("userName");
        userEmail = bundle.getString("userEmail");
        
        mobileFindStr = bundle.getString("mobileFind");
        mobileFind = Utilities.getInstance().StrToHashSet(mobileFindStr, ",");
        mobileUpdateStr = bundle.getString("mobileUpdate");
        mobileUpdate = Utilities.getInstance().StrToHashSet(mobileUpdateStr, ",");
        mobileNotNullableStr = bundle.getString("mobileNotNullable");
        mobileNotNullable = Utilities.getInstance().StrToHashSet(mobileNotNullableStr, ",");
        
        
        fleetFindStr = bundle.getString("fleetFind");
        fleetFind = Utilities.getInstance().StrToHashSet(fleetFindStr, ",");
        fleetUpdateStr = bundle.getString("fleetUpdate");
        fleetUpdate = Utilities.getInstance().StrToHashSet(fleetUpdateStr, ",");
    }

    public static ParseJson getInstance() {
        if (_singleton == null) {
            _singleton = new ParseJson();
        }
        return _singleton;
    }

    public JsonArray parseJSONUpdate(String content, HashSet find, HashSet update, String findStr, String updateStr) {
        String errorMessage = "";

        JsonParser jp = new JsonParser();
        JsonArray obj = null;
        try {
            obj = (JsonArray) jp.parse(content);
        } catch (Exception ignore) {
            throw new JSONMalFormedException("The json does not have the find and update subdocuments.", ErrorCodes.JSON_MAL_FORMED);
        }

        if (obj.size() != 2) {
            throw new JSONMalFormedException("The json does not have the find and update subdocuments.", ErrorCodes.JSON_MAL_FORMED);
        } else {
            JsonObject findObj = (JsonObject) obj.get(0);
            Set<Entry<String, JsonElement>> entrySet = findObj.entrySet();

            if (entrySet.isEmpty()) {
                throw new JSONMalFormedException("Find part: there are no find attributes", ErrorCodes.JSON_MAL_FORMED);
            }

            for (Entry<String, JsonElement> att : entrySet) {
                if (!find.contains(att.getKey())) {
                    errorMessage += "the attribute " + att.getKey() + " in find is not valid, ";
                }
            }
            if (!errorMessage.equals("")) {
                errorMessage += "the valid attributes for are: " + findStr;
                throw new JSONMalFormedException("Find part: " + errorMessage, ErrorCodes.JSON_MAL_FORMED);
            }

            JsonObject updateObjSet = (JsonObject) obj.get(1);
            JsonObject updateObj = (JsonObject) updateObjSet.get("$set");
            entrySet = updateObj.entrySet();

            if (entrySet.isEmpty()) {
                throw new JSONMalFormedException("Update part: there are no find attributes", ErrorCodes.JSON_MAL_FORMED);
            }

            if (entrySet.size() > update.size()) {
                throw new JSONMalFormedException("The json has attributes in update that are not valid. The valid attributes are " + updateStr, ErrorCodes.JSON_MAL_FORMED);
            } else {
                for (Entry<String, JsonElement> att : entrySet) {
                    if (!update.contains(att.getKey())) {
                        errorMessage += "the attribute " + att.getKey() + " in update is not valid, ";
                    }
                }
                if (!errorMessage.equals("")) {
                    errorMessage += "the valid attributes for are: " + updateStr;
                    throw new JSONMalFormedException("Update part: " + errorMessage, ErrorCodes.JSON_MAL_FORMED);
                }
            }

        }

        return obj;
    }

    private JsonArray parseJSONDriverGroupUpdate(JsonArray obj) {
        JsonArray objA = new JsonArray();
        String errorMessage = "";
        JsonObject updateObjSet = (JsonObject) obj.get(1);
        JsonObject updateObj = (JsonObject) updateObjSet.get("$set");
        if (!updateObj.has(driverGroupDocument)) {
            return null;
        } else {
            JsonObject drGroupDocument = (JsonObject) updateObj.get(driverGroupDocument);
            if (!drGroupDocument.has(driverGroupFindStr)) {
                errorMessage += "the attribute " + driverGroupFindStr + " is mandatory and is not subdocument. ";
                errorMessage += "The valid attributes for Driver_Group are: " + driverGroupFindStr + ", " + driverGroupUpdateStr;
                throw new JSONMalFormedException("dr_grp-> subdocument part: " + errorMessage, ErrorCodes.JSON_MAL_FORMED);
            } else {
                //put the json array position 0
                JsonObject jsAux = new JsonObject();
                jsAux.add(driverGroupFindStr, drGroupDocument.get(driverGroupFindStr));
                objA.add(jsAux);
                drGroupDocument.remove(driverGroupFindStr);
            }

            Set<Entry<String, JsonElement>> entrySet = drGroupDocument.entrySet();
            if (entrySet.isEmpty()) {
                errorMessage += "the valid attributes for update Driver_Group are: " + driverGroupUpdateStr;
                throw new JSONMalFormedException("dr_grp-> subdocument part: " + errorMessage, ErrorCodes.JSON_MAL_FORMED);
            }
            for (Entry<String, JsonElement> att : entrySet) {
                if (!driverGroupUpdate.contains(att.getKey())) {
                    errorMessage += "the attribute " + att.getKey() + " in  update is not valid, ";
                }
            }
            if (!errorMessage.equals("")) {
                errorMessage += "the valid attributes for update Driver_Group are: " + driverGroupUpdateStr;
                throw new JSONMalFormedException("dr_grp-> subdocument part: " + errorMessage, ErrorCodes.JSON_MAL_FORMED);
            } else {
                objA.add(drGroupDocument);
            }
        }
        return objA;
    }

    public FindAndSet buildSQLQuery(String content, HashSet find, HashSet update, String findStr, String updateStr) {
        return buildSQLQuery(content, find, update, findStr, updateStr, 0);

    }

    public FindAndSet buildSQLQueryForDriver(String content, HashSet find, HashSet update, String findStr, String updateStr) {
        return buildSQLQuery(content, find, update, findStr, updateStr, 1);

    }
    
    public FindAndSet buildSQLQueryForGroup(String content, HashSet find, HashSet update, String findStr, String updateStr) {
        return buildSQLQuery(content, find, update, findStr, updateStr, 2);

    }

    public FindAndSet buildSQLQueryUpdateForDriverGroup(String find, String update) {
        FindAndSet fas = new FindAndSet();
        JsonParser jp = new JsonParser();
        JsonObject obj = null;
        try {
            obj = (JsonObject) jp.parse(find);
        } catch (Exception ignore) {
            throw new JSONMalFormedException("The json does not have the find and update subdocuments.", ErrorCodes.JSON_MAL_FORMED);
        }

        String findSql = "";
        String updateSql = "";
        Set<Map.Entry<String, JsonElement>> entrySet = obj.entrySet();

        for (Map.Entry<String, JsonElement> att : entrySet) {
            findSql += " [" + att.getKey() + "]= '" + StringEscapeUtils.escapeSql(att.getValue().getAsString()) + "' ,";
        }

        try {
            obj = (JsonObject) jp.parse(update);
        } catch (Exception ignore) {
            throw new JSONMalFormedException("The json does not have the find and update subdocuments.", ErrorCodes.JSON_MAL_FORMED);
        }

        entrySet = obj.entrySet();

        for (Map.Entry<String, JsonElement> att : entrySet) {
            if (att.getValue().isJsonNull()) {
                updateSql += " [" + att.getKey() + "]= null ,";
            } else {
                updateSql += " [" + att.getKey() + "]= '" + StringEscapeUtils.escapeSql(att.getValue().getAsString()) + "' ,";
            }
        }
        if (updateSql.isEmpty()) {
            return null;
        }
        updateSql = updateSql.substring(0, updateSql.length() - 2);
        findSql = findSql.substring(0, findSql.length() - 2);

        fas.setFind(findSql);
        fas.setUpdate(updateSql);

        return fas;

    }

    /**
     * 
     * @param content
     * @param find
     * @param update
     * @param findStr
     * @param updateStr
     * @param object type of object: 0 -> general, 1 -> driver, 2 -> Group
     * @return 
     */
    private FindAndSet buildSQLQuery(String content, HashSet find, HashSet update, String findStr, String updateStr, int object) {
        FindAndSet fas = new FindAndSet();
        fas.setObject(content);
        JsonArray js = parseJSONUpdate(content, find, update, findStr, updateStr);

        JsonArray jsDriverGroup = parseJSONDriverGroupUpdate(js);

        String findSql = "";
        String updateSql = "";

        JsonObject findObj = (JsonObject) js.get(0);
        Set<Map.Entry<String, JsonElement>> entrySet = findObj.entrySet();

        for (Map.Entry<String, JsonElement> att : entrySet) {
            findSql += " [" + att.getKey() + "]= '" + StringEscapeUtils.escapeSql(att.getValue().getAsString()) + "' ,";
            //if is the id
            if(att.getKey().equals("id")){
                try{
                    fas.setId(att.getValue().getAsInt());
                }
                catch(Exception ignore){}
            }
        }

        JsonObject updateObjSet = (JsonObject) js.get(1);
        JsonObject updateObj = (JsonObject) updateObjSet.get("$set");
        entrySet = updateObj.entrySet();

        for (Map.Entry<String, JsonElement> att : entrySet) {
            //if is not a driver and not a driverGroupDocument           AND if is not group and not a groupTags
            if(!(object==1 && att.getKey().equals(driverGroupDocument))  && !(object==2 && att.getKey().equals(groupTags))){ //if is not a driver and not a driverGroupDocument
                if (att.getValue().isJsonNull()) {
                    updateSql += " [" + att.getKey() + "]= null ,";
                } else {
                    updateSql += " [" + att.getKey() + "]= '" + StringEscapeUtils.escapeSql(att.getValue().getAsString()) + "' ,";
                }
            }
            else if(object==2 && att.getKey().equals(groupTags)){//copy tags
                List<String> tags = new ArrayList<String>();
                
                if (!att.getValue().isJsonNull()) {
                    JsonArray jsonArray = att.getValue().getAsJsonArray();
                    if (jsonArray != null) {
                        int len = jsonArray.size();
                        for (int i = 0; i < len; i++) {
                            tags.add(jsonArray.get(i).toString());
                        }
                    }
                }
                fas.setGroupTags(tags);
            }
            
        }

        if (updateSql.length() > 0) {
            updateSql = updateSql.substring(0, updateSql.length() - 2);
        }
        
        findSql = findSql.substring(0, findSql.length() - 2);

        fas.setFind(findSql);
        fas.setUpdate(updateSql);
        if (jsDriverGroup != null) {
            fas.setFindDriverGroup(jsDriverGroup.get(0).toString());
            fas.setUpdateDriverGroup(jsDriverGroup.get(1).toString());
            fas.setFasDriverGroup(buildSQLQueryUpdateForDriverGroup(jsDriverGroup.get(0).toString(), jsDriverGroup.get(1).toString()));
        }

        return fas;
    }
    
    
    
    
    public JsonArray parseJSONUpdateForPoi(String content, HashSet find, HashSet update, String findStr, String updateStr) {
        String errorMessage = "";
        boolean isPoiCategory = false;
        boolean isPoiCategoryGroup = false;

        JsonParser jp = new JsonParser();
        JsonArray obj = null;
        try {
            obj = (JsonArray) jp.parse(content);
        } catch (Exception ignore) {
            throw new JSONMalFormedException("The json does not have the find and update subdocuments.", ErrorCodes.JSON_MAL_FORMED);
        }

        if (obj.size() != 2) {
            throw new JSONMalFormedException("The json does not have the find and update subdocuments.", ErrorCodes.JSON_MAL_FORMED);
        } else {
            JsonObject findObj = (JsonObject) obj.get(0);
            Set<Entry<String, JsonElement>> entrySet = findObj.entrySet();

            if (entrySet.isEmpty()) {
                throw new JSONMalFormedException("Find part: there are no find attributes", ErrorCodes.JSON_MAL_FORMED);
            }

            for (Entry<String, JsonElement> att : entrySet) {
                if (!find.contains(att.getKey())) {
                    errorMessage += "the attribute " + att.getKey() + " in find is not valid, ";
                }
            }
            if (!errorMessage.equals("")) {
                errorMessage += "the valid attributes for are: " + findStr;
                throw new JSONMalFormedException("Find part: " + errorMessage, ErrorCodes.JSON_MAL_FORMED);
            }

            JsonObject updateObjSet = (JsonObject) obj.get(1);
            JsonObject updateObj = (JsonObject) updateObjSet.get("$set");
            entrySet = updateObj.entrySet();

            if (entrySet.isEmpty()) {
                throw new JSONMalFormedException("Update part: there are no find attributes", ErrorCodes.JSON_MAL_FORMED);
            }

            if (entrySet.size() > update.size()) {
                throw new JSONMalFormedException("The json has attributes in update that are not valid. The valid attributes are " + updateStr, ErrorCodes.JSON_MAL_FORMED);
            } else {
                for (Entry<String, JsonElement> att : entrySet) {
                    String attr = att.getKey();                    
                        
                    if (!update.contains(attr)) {
                        errorMessage += "the attribute " + att.getKey() + " in update is not valid, ";
                    }
                    else{
                        if(attr.equals(poiCategory)){
                            isPoiCategory = true;
                            if (att.getValue().isJsonNull()) {
                                errorMessage += "the attribute " + att.getKey() + " in update cannot be null, ";
                            }
                        }
                        else if(attr.equals(poiCategoryGroup)){
                            isPoiCategoryGroup = true;
                            if (att.getValue().isJsonNull()) {
                                errorMessage += "the attribute " + att.getKey() + " in update cannot be null, ";
                            }
                        }
                        else if(attr.equals(poiDescription)){
                            if (att.getValue().isJsonNull()) {
                                errorMessage += "the attribute " + att.getKey() + " in update cannot be null, ";
                            }
                        }
                        else if(attr.equals(poiMax_auth_stop_time)){
                            if (att.getValue().isJsonNull()) {
                                errorMessage += "the attribute " + att.getKey() + " in update cannot be null, ";
                            }
                        }
                    }
                }
                if (!errorMessage.equals("")) {
                    errorMessage += "the valid attributes for are: " + updateStr;
                    throw new JSONMalFormedException("Update part: " + errorMessage, ErrorCodes.JSON_MAL_FORMED);
                }
                
                if(isPoiCategory && !isPoiCategoryGroup){
                    errorMessage += "The "+poiCategory+" is present but the "+poiCategoryGroup+" is not";
                    throw new JSONMalFormedException("Update part: " + errorMessage, ErrorCodes.JSON_MAL_FORMED);
                }
                else if(!isPoiCategory && isPoiCategoryGroup){
                    
                    errorMessage += "The "+poiCategory+" is present but the "+poiCategoryGroup+" is not";
                    throw new JSONMalFormedException("Update part: " + errorMessage, ErrorCodes.JSON_MAL_FORMED);
                }
                
            }

        }

        return obj;
    }
    
    public FindAndSet buildSQLQueryForPoi(String content, HashSet find, HashSet update, String findStr, String updateStr) {
        FindAndSet fas = new FindAndSet();
        fas.setObject(content);
        JsonArray js = parseJSONUpdateForPoi(content, find, update, findStr, updateStr);
        
        boolean setPoi = false;
        Poi poi = new Poi();

        String findSql = "";
        String updateSql = "";

        JsonObject findObj = (JsonObject) js.get(0);
        Set<Map.Entry<String, JsonElement>> entrySet = findObj.entrySet();

        for (Map.Entry<String, JsonElement> att : entrySet) {
            findSql += " [" + att.getKey() + "]= '" + StringEscapeUtils.escapeSql(att.getValue().getAsString()) + "' ,";
        }

        JsonObject updateObjSet = (JsonObject) js.get(1);
        JsonObject updateObj = (JsonObject) updateObjSet.get("$set");
        entrySet = updateObj.entrySet();

        for (Map.Entry<String, JsonElement> att : entrySet) {  
            String key = att.getKey();
            //if the key is not for the xml part or the part of [poi_poi_category](  id_category or id_group)
            if (!poiXml.contains(key) && !key.equals(poiCategory) && !key.equals(poiCategoryGroup)) {
                if (att.getValue().isJsonNull()) {
                    updateSql += " [" + att.getKey() + "]= null ,";
                } else {
                    updateSql += " [" + att.getKey() + "]= '" + StringEscapeUtils.escapeSql(att.getValue().getAsString()) + "' ,";
                }       
            }
            else{
                //if there is an attribute for the xml part or the part of [poi_poi_category](  id_category or id_group)
                //build the Poi object also
                if(!setPoi){
                    setPoi = true;
                    Gson gson = new Gson();
                    poi = gson.fromJson(updateObj, Poi.class);
                }
            }
        }

        if (updateSql.length() > 0) {
            updateSql = updateSql.substring(0, updateSql.length() - 2);
        }
        findSql = findSql.substring(0, findSql.length() - 2);

        fas.setFind(findSql);
        fas.setUpdate(updateSql);
        if(setPoi)
            fas.setPoi(poi);

        return fas;
    }

    public HashSet getFleetFind() {
        return fleetFind;
    }

    public void setFleetFind(HashSet fleetFind) {
        ParseJson.fleetFind = fleetFind;
    }

    public String getFleetFindStr() {
        return fleetFindStr;
    }

    public void setFleetFindStr(String fleetFindStr) {
        ParseJson.fleetFindStr = fleetFindStr;
    }

    public HashSet getFleetUpdate() {
        return fleetUpdate;
    }

    public void setFleetUpdate(HashSet fleetUpdate) {
        ParseJson.fleetUpdate = fleetUpdate;
    }

    public String getFleetUpdateStr() {
        return fleetUpdateStr;
    }

    public void setFleetUpdateStr(String fleetUpdateStr) {
        ParseJson.fleetUpdateStr = fleetUpdateStr;
    }
    
    

    public HashSet getTrailerFind() {
        return trailerFind;
    }

    public String getTrailerFindStr() {
        return trailerFindStr;
    }

    public HashSet getTrailerUpdate() {
        return trailerUpdate;
    }

    public String getTrailerUpdateStr() {
        return trailerUpdateStr;
    }

    public HashSet getGroupFind() {
        return groupFind;
    }

    public String getGroupFindStr() {
        return groupFindStr;
    }

    public HashSet getGroupUpdate() {
        return groupUpdate;
    }

    public String getGroupUpdateStr() {
        return groupUpdateStr;
    }

    public HashSet getSubgroupFind() {
        return subgroupFind;
    }

    public String getSubgroupFindStr() {
        return subgroupFindStr;
    }

    public HashSet getSubgroupUpdate() {
        return subgroupUpdate;
    }

    public String getSubgroupUpdateStr() {
        return subgroupUpdateStr;
    }

    public HashSet getUserFind() {
        return userFind;
    }

    public String getUserFindStr() {
        return userFindStr;
    }

    public HashSet getUserUpdate() {
        return userUpdate;
    }

    public String getUserUpdateStr() {
        return userUpdateStr;
    }

    public HashSet getDriverFind() {
        return driverFind;
    }

    public void setDriverFind(HashSet driverFind) {
        ParseJson.driverFind = driverFind;
    }

    public String getDriverFindStr() {
        return driverFindStr;
    }

    public void setDriverFindStr(String driverFindStr) {
        ParseJson.driverFindStr = driverFindStr;
    }

    public String getDriverGroupDocument() {
        return driverGroupDocument;
    }

    public void setDriverGroupDocument(String driverGroupDocument) {
        ParseJson.driverGroupDocument = driverGroupDocument;
    }

    public HashSet getDriverGroupFind() {
        return driverGroupFind;
    }

    public void setDriverGroupFind(HashSet driverGroupFind) {
        ParseJson.driverGroupFind = driverGroupFind;
    }

    public String getDriverGroupFindStr() {
        return driverGroupFindStr;
    }

    public void setDriverGroupFindStr(String driverGroupFindStr) {
        ParseJson.driverGroupFindStr = driverGroupFindStr;
    }

    public HashSet getDriverGroupUpdate() {
        return driverGroupUpdate;
    }

    public void setDriverGroupUpdate(HashSet driverGroupUpdate) {
        ParseJson.driverGroupUpdate = driverGroupUpdate;
    }

    public String getDriverGroupUpdateStr() {
        return driverGroupUpdateStr;
    }

    public void setDriverGroupUpdateStr(String driverGroupUpdateStr) {
        ParseJson.driverGroupUpdateStr = driverGroupUpdateStr;
    }

    public HashSet getDriverUpdate() {
        return driverUpdate;
    }

    public void setDriverUpdate(HashSet driverUpdate) {
        ParseJson.driverUpdate = driverUpdate;
    }

    public String getDriverUpdateStr() {
        return driverUpdateStr;
    }

    public void setDriverUpdateStr(String driverUpdateStr) {
        ParseJson.driverUpdateStr = driverUpdateStr;
    }

    public String getPoiCategory() {
        return poiCategory;
    }

    public void setPoiCategory(String poiCategory) {
        ParseJson.poiCategory = poiCategory;
    }

    public String getPoiCategoryGroup() {
        return poiCategoryGroup;
    }

    public void setPoiCategoryGroup(String poiCategoryGroup) {
        ParseJson.poiCategoryGroup = poiCategoryGroup;
    }

    public HashSet getPoiFind() {
        return poiFind;
    }

    public void setPoiFind(HashSet poiFind) {
        ParseJson.poiFind = poiFind;
    }

    public String getPoiFindStr() {
        return poiFindStr;
    }

    public void setPoiFindStr(String poiFindStr) {
        ParseJson.poiFindStr = poiFindStr;
    }

    public HashSet getPoiUpdate() {
        return poiUpdate;
    }

    public void setPoiUpdate(HashSet poiUpdate) {
        ParseJson.poiUpdate = poiUpdate;
    }

    public String getPoiUpdateStr() {
        return poiUpdateStr;
    }

    public void setPoiUpdateStr(String poiUpdateStr) {
        ParseJson.poiUpdateStr = poiUpdateStr;
    }

    public HashSet getPoiXml() {
        return poiXml;
    }

    public void setPoiXml(HashSet poiXml) {
        ParseJson.poiXml = poiXml;
    }

    public String getPoiXmlStr() {
        return poiXmlStr;
    }

    public void setPoiXmlStr(String poiXmlStr) {
        ParseJson.poiXmlStr = poiXmlStr;
    }

    /**
     * <parameters>
        <description>MADEIRA</description>
        <timestamp>2011-10-06 13:15:49</timestamp>
        <max_auth_stop_time>30</max_auth_stop_time>
        </parameters>
     * @param poi 
     */
    public String createXml(Poi poi) {
        String toRet = null;
        try {
            Document doc = null;
            DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = docFactory.newDocumentBuilder();

            //root elements
            doc = docBuilder.newDocument();

            Element rootElement = doc.createElement("parameters");
            doc.appendChild(rootElement);

            //add description element
            Element description = doc.createElement("description");
            description.appendChild(doc.createTextNode(poi.getDescription()));
            rootElement.appendChild(description);
            
            //add max_auth_stop_time element
            Element max_auth_stop_time = doc.createElement("max_auth_stop_time");
            max_auth_stop_time.appendChild(doc.createTextNode(poi.getMax_auth_stop_time()));
            rootElement.appendChild(max_auth_stop_time);

            //add metadata
            if(poi.getMetadata()!=null){
                JsonParser jp = new JsonParser();
                LinkedHashMap metadata = null;
                try {
                    metadata = poi.getMetadata();
                } catch (Exception ignore) {
                    throw new JSONMalFormedException("Metadata mal formed.", ErrorCodes.JSON_MAL_FORMED);
                }
                Set entrySet = metadata.keySet();
                for (Iterator it = entrySet.iterator(); it.hasNext();) {
                    String att = (String) it.next();
                        Element metadatakey = doc.createElement(att);
                        metadatakey.appendChild(doc.createTextNode(metadata.get(att).toString()));
                        rootElement.appendChild(metadatakey);                   
                }
            }
            

            // transform the Document into a String
            DOMSource domSource = new DOMSource(doc);
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer transformer = tf.newTransformer();
            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            transformer.setOutputProperty(OutputKeys.METHOD, "xml");
            transformer.setOutputProperty(OutputKeys.ENCODING,"ISO-8859-1");
            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            java.io.StringWriter sw = new java.io.StringWriter();
            StreamResult sr = new StreamResult(sw);
            transformer.transform(domSource, sr);
            toRet = StringEscapeUtils.escapeSql(sw.toString());
        } catch (Exception ex) {
            throw new JSONMalFormedException("Xml incorrect.", ErrorCodes.JSON_MAL_FORMED);
        }
        
        return toRet;


    }
    
    
    /**
     * <parameters>
        <description>MADEIRA</description>
        <timestamp>2011-10-06 13:15:49</timestamp>
        <max_auth_stop_time>30</max_auth_stop_time>
        </parameters>
     * @param poi 
     */
    public String updateXml(Poi poi, String previousXml) {
        String toRet = null;
        try {
            
            Document doc = null;
            DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = docFactory.newDocumentBuilder();

            //root elements
            doc = docBuilder.parse(new InputSource(new StringReader(previousXml)));

            Element rootElement = (Element) doc.getElementsByTagName("parameters").item(0);            
            //update description element
            if(poi.getDescription()!=null){
                Element description = doc.createElement("description");
                description.appendChild(doc.createTextNode(poi.getDescription()));
                rootElement.replaceChild(description, (Element) rootElement.getElementsByTagName("description").item(0));
            }
            
            //update max_auth_stop_time element
            if(poi.getMax_auth_stop_time()!=null){
                Element max_auth_stop_time = doc.createElement("max_auth_stop_time");
                max_auth_stop_time.appendChild(doc.createTextNode(poi.getMax_auth_stop_time()));
                rootElement.replaceChild(max_auth_stop_time, (Element) rootElement.getElementsByTagName("max_auth_stop_time").item(0));
            }

            //add metadata
            if(poi.getMetadata()!=null){
                JsonParser jp = new JsonParser();
                LinkedHashMap metadata = null;
                try {
                    metadata = poi.getMetadata();
                } catch (Exception ignore) {
                    throw new JSONMalFormedException("Metadata mal formed.", ErrorCodes.JSON_MAL_FORMED);
                }
                Set entrySet = metadata.keySet();
                //iterate json metadata
                for (Iterator it = entrySet.iterator(); it.hasNext();) {
                    String att = (String) it.next();
                    //get list of nodes with this "att" element name
                    NodeList elementsByTagName = rootElement.getElementsByTagName(att);
                    //
                    if(elementsByTagName.getLength()>0){
                        Element metadatakeyInXml = (Element)elementsByTagName.item(0);
                        if(metadata.get(att)== null || metadata.get(att).toString().equals("null")){
                            rootElement.removeChild(metadatakeyInXml);
                        }else {
                            
                            Element metadatakey = doc.createElement(att);
                            metadatakey.appendChild(doc.createTextNode(metadata.get(att).toString()));
                            rootElement.replaceChild(metadatakey,metadatakeyInXml);
                        }
                        
                        
                    }
                    else if(metadata.get(att)!= null && ! metadata.get(att).toString().equals("null")){
                        Element metadatakey = doc.createElement(att);
                        metadatakey.appendChild(doc.createTextNode(metadata.get(att).toString()));
                        rootElement.appendChild(metadatakey);                   
                    }
                }
            }
            

            // transform the Document into a String
            DOMSource domSource = new DOMSource(doc);
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer transformer = tf.newTransformer();
            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            transformer.setOutputProperty(OutputKeys.METHOD, "xml");
            transformer.setOutputProperty(OutputKeys.ENCODING,"ISO-8859-1");
            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            java.io.StringWriter sw = new java.io.StringWriter();
            StreamResult sr = new StreamResult(sw);
            transformer.transform(domSource, sr);
            toRet = StringEscapeUtils.escapeSql(sw.toString());
        } catch (Exception ex) {
            throw new JSONMalFormedException("Xml incorrect.", ErrorCodes.JSON_MAL_FORMED);
        }
        
        return toRet;


    }
    
    /**
     * from content(JSON) get the name and email, to be used in mailChimp
     * @param content
     * @return 
     */
    public User getUserUpdate(String content){
        User toRet = new User();        
        JsonParser jp = new JsonParser();
        JsonArray obj = null;
        try {
            obj = (JsonArray) jp.parse(content);
        } catch (Exception ignore) {
            throw new JSONMalFormedException("The json does not have the find and update subdocuments.", ErrorCodes.JSON_MAL_FORMED);
        }
        //get userId
        JsonObject findObj = (JsonObject) obj.get(0);
        if(findObj.has(userFindStr))
            toRet.setId(findObj.get(userFindStr).getAsInt());
        
        //get name and email
        JsonObject updateObjSet = (JsonObject) obj.get(1);
        JsonObject updateObj = (JsonObject) updateObjSet.get("$set");
                
        if(updateObj.has(userName))
            toRet.setName(updateObj.get(userName).getAsString());
        
        if(updateObj.has(userEmail))
            toRet.setEmail(updateObj.get(userEmail).getAsString());
        
        
        return toRet;
    }
    
    
    /**
     * 
     * @param content
     * @param find
     * @param update
     * @param findStr
     * @param updateStr
     * @param object type of object: 0 -> general, 1 -> driver, 2 -> Group
     * @return 
     */
    public MobileUpdate getMobileUpdateValidated(String content) {
        MobileUpdate mu = new MobileUpdate();
        
        JsonArray js = parseJSONUpdate(content, mobileFind, mobileUpdate,mobileFindStr, mobileUpdateStr);


        JsonObject findObj = (JsonObject) js.get(0);
        Set<Map.Entry<String, JsonElement>> entrySet = findObj.entrySet();

        for (Map.Entry<String, JsonElement> att : entrySet) {            
            //if is the id
            if(att.getKey().equals("uid")){
                try{
                    mu.setUid(att.getValue().getAsInt());
                }
                catch(Exception ignore){}
            }
        }

        JsonObject updateObjSet = (JsonObject) js.get(1);
        JsonObject updateObj = (JsonObject) updateObjSet.get("$set");
        entrySet = updateObj.entrySet();

        for (Map.Entry<String, JsonElement> att : entrySet) {
            
                String keyStr = att.getKey();
                
                if (att.getValue().isJsonNull()) {
                    
                    if(mobileNotNullable.contains(keyStr)){
                         throw new JSONMalFormedException("Find part: the attribute " + att.getKey() + " in update is not valid, cannot be null", ErrorCodes.GENERAL_ERROR);
                    }
                    
                    if(keyStr.equals("vehicle_type")){
                        mu.setVehicle_type(null);
                        mu.setVehicle_typeFlag(true);
                    }
                    else if(keyStr.equals("brand")){
                        mu.setBrand(null);
                        mu.setBrandFlag(true);
                    }
                    else if(keyStr.equals("model")){
                        mu.setModel(null);
                        mu.setModelFlag(true);
                    }
                    else if(keyStr.equals("owner")){
                        mu.setOwner(null);
                        mu.setOwnerFlag(true);
                    }
                    
                } 
                else {
                    
                   if(keyStr.equals("alias")){
                        mu.setAlias(StringEscapeUtils.escapeSql(att.getValue().getAsString()));
                        mu.setAliasFlag(true);
                    }
                    else if(keyStr.equals("license_plate")){
                        mu.setLicense_plate(StringEscapeUtils.escapeSql(att.getValue().getAsString()));
                        mu.setLicense_plateFlag(true);
                    }
                    else if(keyStr.equals("serial_number")){
                        mu.setSerial_number(StringEscapeUtils.escapeSql(att.getValue().getAsString()));
                        mu.setSerial_numberFlag(true);
                    }
                    else if(keyStr.equals("imei")){
                        mu.setImei(StringEscapeUtils.escapeSql(att.getValue().getAsString()));
                        mu.setImeiFlag(true);
                    }
                    else if(keyStr.equals("gsm_number")){
                        mu.setGsm_number(StringEscapeUtils.escapeSql(att.getValue().getAsString()));
                        mu.setGsm_numberFlag(true);
                    }
                    else if(keyStr.equals("iccid")){
                        mu.setIccid(StringEscapeUtils.escapeSql(att.getValue().getAsString()));
                        mu.setIccidFlag(true);
                    }
                    else if(keyStr.equals("equipment_type")){
                        mu.setEquipment_type(StringEscapeUtils.escapeSql(att.getValue().getAsString()));
                        mu.setEquipment_typeFlag(true);
                    }                    
                    else if(keyStr.equals("id_image")){
                        mu.setId_image(StringEscapeUtils.escapeSql(att.getValue().getAsString()));
                        mu.setId_imageFlag(true);
                    }
                    else if(keyStr.equals("vehicle_type")){
                        mu.setVehicle_type(StringEscapeUtils.escapeSql(att.getValue().getAsString()));
                        mu.setVehicle_typeFlag(true);
                    }
                    else if(keyStr.equals("brand")){
                        mu.setBrand(StringEscapeUtils.escapeSql(att.getValue().getAsString()));
                        mu.setBrandFlag(true);
                    }
                    else if(keyStr.equals("model")){
                        mu.setModel(StringEscapeUtils.escapeSql(att.getValue().getAsString()));
                        mu.setModelFlag(true);
                    }
                    else if(keyStr.equals("owner")){
                        mu.setOwner(StringEscapeUtils.escapeSql(att.getValue().getAsString()));
                        mu.setOwnerFlag(true);
                    }
                    else if(keyStr.equals("fuel_error_coefficient")){
                        mu.setFuel_error_coefficient(StringEscapeUtils.escapeSql(att.getValue().getAsString()));
                        mu.setFuel_error_coefficientFlag(true);
                    }
                   
                }
        }
        
        return mu;
    }
    
    
    
    
    /**
     * 
     * @param content
     * @return 
     */
    public Fleet getFleetUpdateValidated(String content) {
        Fleet mu = new Fleet();
        
        JsonArray js = parseJSONUpdate(content,fleetFind, fleetUpdate, fleetFindStr, fleetUpdateStr);


        JsonObject findObj = (JsonObject) js.get(0);
        Set<Map.Entry<String, JsonElement>> entrySet = findObj.entrySet();

        for (Map.Entry<String, JsonElement> att : entrySet) {            
            //if is the id
            if(att.getKey().equals("id")){
                try{
                    mu.setId(att.getValue().getAsInt());
                }
                catch(Exception ignore){}
            }
        }

        JsonObject updateObjSet = (JsonObject) js.get(1);
        JsonObject updateObj = (JsonObject) updateObjSet.get("$set");
        entrySet = updateObj.entrySet();

        for (Map.Entry<String, JsonElement> att : entrySet) {
            
            String keyStr = att.getKey();

            if(keyStr.equals("alias")){
                if (att.getValue().isJsonNull())
                    throw new JSONMalFormedException("Find part: the attribute " + att.getKey() + " in update is not valid, cannot be null", ErrorCodes.GENERAL_ERROR);

                mu.setAlias(StringEscapeUtils.escapeSql(att.getValue().getAsString()));
            }
        }
        
        return mu;
    }
    
    
}
